#pragma once
#include <functional>
#include "Common.hpp"
#include <jsoncpp/json/json.h>

const std::string _text_sep = "/r/n";



class Request{
public:
    Request(){}

    Request(int left_num, int right_num, char opr)
        :_left_num(left_num),
        _right_num(right_num),
        _opr(opr)
    {}
    ~Request(){}

    std::string Serialize(){
        Json::Value root;
        root["left_num"] = _left_num;
        root["right_num"] = _right_num;
        root["opr"] = _opr;

        Json::FastWriter writer;
        std::string req = writer.write(root);
        return req;
    }

    bool DeSerialize(std::string& in){
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if(ok){
            _left_num = root["left_num"].asInt();
            _right_num = root["right_num"].asInt();
            _opr = root["opr"].asInt();
        }
        return ok;
    }

    int Get_Left_Num() const {return _left_num;}
    int Get_Right_Num() const {return _right_num;}
    int Get_Opr() const {return _opr;}

private:
    int _left_num;
    int _right_num;
    char _opr;
};


class Response{
public:
    Response(){}

    Response(int result, int ret_code)
        :_result(result), _ret_code(ret_code)
    {}
    ~Response(){}

    std::string Serialize(){
        Json::Value root;
        root["result"] = _result;
        root["ret_code"] = _ret_code;

        Json::FastWriter writer;
        std::string resp = writer.write(root);
        return resp;
    }

    bool DeSerialize(std::string& in){
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);

        if(ok){
            _result = root["result"].asInt();
            _ret_code = root["ret_code"].asInt();
        }
        return ok;
    }

    void SetResult(int result) {
        _result = result;
    }

    void SetRetCode(int ret_code) {
        _ret_code = ret_code;
    }

    void Show(){
        std::cout << "[result : ret_code] -> [" << _result << " : " << _ret_code << "]" << std::endl;
    }
    
private:
    int _result;
    int _ret_code;
};

using protocol_cal_t = std::function<Response(int, int, char)>;
//有效报文是：
//{"x": 10, "y" : 20, "oper" : '+'}
//也可能不足一条，可能刚好一条，也可能比一条多
//所以，需要对这个协议做进一步规定
class Protocol_Netcal{
public:
    Protocol_Netcal(){}

    Protocol_Netcal(protocol_cal_t cal)
        :_cal(cal)
    {}
    ~Protocol_Netcal(){}

//{"x": 10, "y" : 20, "oper" : '+'} 
//↓
//50/r/n{"x": 10, "y" : 20, "oper" : '+'}/r/n
    std::string Encode(std::string& json_str){
        std::string res = std::to_string(json_str.size());
        return res + _text_sep + json_str + _text_sep;
    }

//50/r/n{"x": 10, "y" : 20, "oper" : '+'}/r/n
//↓
//{"x": 10, "y" : 20, "oper" : '+'} 
    bool Decode(std::string& inbuffer, std::string* json_str){
        size_t pos = inbuffer.find(_text_sep);
        if(pos == std::string::npos) return false;
        
        //1.一定保证当前的缓冲区内的报文一定是有数字的，也就是有效报文的长度
        int package_len = std::stoi(inbuffer.substr(0, pos)); //有效报文的长度
        int package_len_int = (inbuffer.substr(0, pos)).size();//指向报文有效长度的那个数字的长度

        //规定，只有当前缓冲区内包含至少一个有效的(编码后的)报文，我们才做Decode
        int target_len = package_len_int + package_len + 2 * _text_sep.size();
        if(inbuffer.size() < target_len) return false;

        //这里，就一定能够保证当前缓冲区内有一个有效的报文 -> 进行Decode，然后移除缓冲区
        (*json_str).clear();
        *json_str = inbuffer.substr(package_len_int + _text_sep.size(), package_len);//package_len_int
        inbuffer.erase(0, target_len);
        return true;
    }


    void GetRequest(std::shared_ptr<Socket> socket, const InetAddr& addr){
        std::string readbuffer;
        //1.从socket读取由对应远端发来的消息（addr已经是服务器accept的一个远端地址）
        while(1){
            int n = socket->Recv(&readbuffer);
            if(n > 0){
            //2.远端发来一个已序列化的请求 -> Decode（现在希望的是，如果说缓冲区内有多个完整报文，都要处理）
                std::string req_json;
                while(Decode(readbuffer, &req_json)){
                    LOG(LogLevel::DEBUG) << addr.GetFormatStr() << " 请求: " << req_json;
                    //3.反序列化
                    Request req;
                    bool ok = req.DeSerialize(req_json);
                    if(!ok) continue;

                    //4.进行计算 //TODO...
                    Response resp = _cal(req.Get_Left_Num(), req.Get_Right_Num(), req.Get_Opr());

                     //5.序列化 + Encode
                    std::string res_json = resp.Serialize();
                    std::string snd_str = Encode(res_json);

                    //6.发送
                    socket->Send(snd_str);
                }
            /* //2.远端发来一个已序列化的请求 -> Decode
                bool ok = Decode(readbuffer, &req_json);
                if(!ok) continue;
            //3.反序列化
                Request req;
                req.DeSerialize(req_json);
                
            //4.进行计算
                Response resp = _cal(req.Get_Left_Num(), req.Get_Right_Num(), req.Get_Opr());

            //5.序列化 + Encode
                std::string res_json = resp.Serialize();
                std::string snd_str = Encode(res_json);
            //6.发送
                socket->Send(snd_str); */
            }
            else if(n == 0){
                LOG(LogLevel::INFO) << "client quit : " << addr.GetFormatStr();
                break;
            }
            else{
                LOG(LogLevel::WARNING) << "read error : " << addr.GetFormatStr();
                break;
            }
        }
    }

    bool GetResponse(std::shared_ptr<Socket> socket, Response& resp, std::string* inbuffer){
        while(1){
            int n = socket->Recv(inbuffer);
            if(n > 0){
                //1.Decode
                std::string res_json;
                while(Decode(*inbuffer, &res_json)){
                    //2.反序列化
                    resp.DeSerialize(res_json);
                }
                return true;
            }
            else if(n == 0){
                LOG(LogLevel::INFO) << "server exit";
                return false;
            }
            else{
                LOG(LogLevel::FATAL) << "server error";
                return false;
            }
        }
    }


    std::string BulidRequestStr(int left, int right, char opr){
        //1.先构造请求Request
        Request req(left, right, opr);
        //2.序列化
        std::string req_json = req.Serialize();
        //3.Encode
        return Encode(req_json);
    }




private:
    protocol_cal_t _cal;
};